/**
 * Pawn Class
 * Uses as parent for x-com and alien pawns classes and has public functions
 */
class x_Pawn extends UDKPawn dependson(x_Weapons);

//=============================================================================
// Variables
//=============================================================================
struct DefenceParameters
{
	var int Head;
	var int Torso;
	var int Arms;
	var int Legs;
	var int Other;
};

var DefenceParameters                                   Defence;
var(XCOM_Data) editinline x_Data_Pawn					Data; //x-com and aliens Data system
var string                                              ArmorIcon; //icon for HUD drag and drop
var class<x_SoundGroup>                                 SoundGroupClass; // sounds

var DynamicLightEnvironmentComponent                    LightEnvironment;

var name                                                WeaponSocket;

var bool                                                bIsDied;

var EPhysics                                            DefaultPhysics; // Default physics state

var AnimNodeSlot                                        FullBodyAnimSlot; //Slot node used for playing full body anims.
var AnimNodeSlot                                        TopHalfAnimSlot; // Slot node used for playing animations only on the top half.

/** Array of bodies that should not have joint drive applied. */
var array<name> NoDriveBodies;

//=============================================================================
// Functions: General
//=============================================================================
event PostBeginPlay()
{
	Super.PostBeginPlay();
	SetPhysics(DefaultPhysics);
	//Data =  new(self)class'x_Data_Pawn';
	Data.InitStrings();
	Data.InitData();
}

function UpdateParameters(optional int aExpQuantity)
{
	if (aExpQuantity != 0) Data.GiveExperience(aExpQuantity);
	HealthMax = Data.Health;
	Health = HealthMax;
}

/** Set various basic properties for this Pawn based on the character class metadata */
simulated function SetCharacterClassFromInfo()
{
	local int i;

	// Make sure bEnableFullAnimWeightBodies is only TRUE if it needs to be (PhysicsAsset has flappy bits)
	Mesh.bEnableFullAnimWeightBodies = FALSE;
	for(i=0; i<Mesh.PhysicsAsset.BodySetup.length && !Mesh.bEnableFullAnimWeightBodies; i++)
	{
		// See if a bone has bAlwaysFullAnimWeight set and also
		if( Mesh.PhysicsAsset.BodySetup[i].bAlwaysFullAnimWeight &&
			Mesh.MatchRefBone(Mesh.PhysicsAsset.BodySetup[i].BoneName) != INDEX_NONE)
		{
			Mesh.bEnableFullAnimWeightBodies = TRUE;
		}
	}

	//Overlay meshes for effects
	if (OverlayMesh != None)
	{
		OverlayMesh.SetSkeletalMesh(Mesh.SkeletalMesh);
		OverlayMesh.SetParentAnimComponent(Mesh);
	}

	//BaseTranslationOffset = CurrCharClassInfo.Default.BaseTranslationOffset;
	CrouchTranslationOffset = BaseTranslationOffset + CylinderComponent.Default.CollisionHeight - CrouchHeight;

	// Make sure physics is in the correct state.
	// Rebuild array of bodies to not apply joint drive to.
	NoDriveBodies.length = 0;
	for( i=0; i<Mesh.PhysicsAsset.BodySetup.Length; i++)
	{
		if(Mesh.PhysicsAsset.BodySetup[i].bAlwaysFullAnimWeight)
		{
			NoDriveBodies.AddItem(Mesh.PhysicsAsset.BodySetup[i].BoneName);
		}
	}

	// Reset physics state.
	bIsHoverboardAnimPawn = FALSE;
	ResetCharPhysState();
}

/** Create an inventory item from Archetype rather than direct class reference */
event final Inventory CreateInventoryFromTemplate( Actor InventoryActorTemplate, optional bool bDoNotActivate )
{
	if ( InvManager != None )
		return x_InventoryManager(InvManager).CreateInventoryFromTemplate( InventoryActorTemplate, bDoNotActivate );

	return None;
}
event final Inventory CreateInventoryFromName( string aName, optional bool aDoNotActivate )
{
	if ( InvManager != None )
		return x_InventoryManager(InvManager).CreateInventoryFromName( aName, aDoNotActivate );

	return None;
}

simulated function ResetCharPhysState()
{
	if(Mesh.PhysicsAssetInstance != None)
	{
		// Now set up the physics based on what we are currently doing.
		if(Physics == PHYS_RigidBody)
		{
			// Ragdoll case
			Mesh.PhysicsAssetInstance.SetAllBodiesFixed(FALSE);
			SetPawnRBChannels(TRUE);
			SetHandIKEnabled(FALSE);
		}
		else
		{
			// Normal case
			Mesh.PhysicsAssetInstance.SetAllBodiesFixed(TRUE);
			Mesh.PhysicsAssetInstance.SetFullAnimWeightBonesFixed(FALSE, Mesh);
			SetPawnRBChannels(FALSE);
			SetHandIKEnabled(TRUE);
		}
	}
}

simulated function SetPawnRBChannels(bool bRagdollMode)
{
	if(bRagdollMode)
	{
		Mesh.SetRBChannel(RBCC_Pawn);
		Mesh.SetRBCollidesWithChannel(RBCC_Default,TRUE);
		Mesh.SetRBCollidesWithChannel(RBCC_Pawn,TRUE);
		Mesh.SetRBCollidesWithChannel(RBCC_Vehicle,TRUE);
		Mesh.SetRBCollidesWithChannel(RBCC_Untitled3,FALSE);
		Mesh.SetRBCollidesWithChannel(RBCC_BlockingVolume,TRUE);
	}
	else
	{
		Mesh.SetRBChannel(RBCC_Untitled3);
		Mesh.SetRBCollidesWithChannel(RBCC_Default,FALSE);
		Mesh.SetRBCollidesWithChannel(RBCC_Pawn,FALSE);
		Mesh.SetRBCollidesWithChannel(RBCC_Vehicle,FALSE);
		Mesh.SetRBCollidesWithChannel(RBCC_Untitled3,TRUE);
		Mesh.SetRBCollidesWithChannel(RBCC_BlockingVolume,FALSE);
	}
}

simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
{
	if (SkelComp == Mesh)
	{
		LeftLegControl = SkelControlFootPlacement(Mesh.FindSkelControl(LeftFootControlName));
		RightLegControl = SkelControlFootPlacement(Mesh.FindSkelControl(RightFootControlName));
		FullBodyAnimSlot = AnimNodeSlot(Mesh.FindAnimNode('FullBodySlot'));
		TopHalfAnimSlot = AnimNodeSlot(Mesh.FindAnimNode('TopHalfSlot'));

		LeftHandIK = SkelControlLimb( mesh.FindSkelControl('LeftHandIK') );

		RightHandIK = SkelControlLimb( mesh.FindSkelControl('RightHandIK') );

		RootRotControl = SkelControlSingleBone( mesh.FindSkelControl('RootRot') );
		AimNode = AnimNodeAimOffset( mesh.FindAnimNode('AimNode') );
		GunRecoilNode = GameSkelCtrl_Recoil( mesh.FindSkelControl('GunRecoilNode') );
		LeftRecoilNode = GameSkelCtrl_Recoil( mesh.FindSkelControl('LeftRecoilNode') );
		RightRecoilNode = GameSkelCtrl_Recoil( mesh.FindSkelControl('RightRecoilNode') );

		FlyingDirOffset = AnimNodeAimOffset( mesh.FindAnimNode('FlyingDirOffset') );
		/*
		foreach mesh.AllAnimNodes(class'MyAnimBlendByWeaponType', BlendByWeaponType) 
		{
			WeaponTypeAnimNodes[WeaponTypeAnimNodes.Length] = BlendByWeaponType;
		}
		*/
	}
}

/** reattaches the mesh component, because settings were updated */
simulated function ReattachMesh()
{
	DetachComponent(Mesh);
	AttachComponent(Mesh);
	EnsureOverlayComponentLast();
}

/** reattaches the mesh component, because settings were updated */
simulated function ReattachWeaponMesh()
{
	//DetachComponent(self.Weapon.Mesh);
	//AttachComponent(self.Weapon.Mesh);
	//EnsureOverlayComponentLast();
	x_Weapons(self.weapon).ReattachWeaponMesh();
	
}

/** Change the type of weapon animation we are playing. */
simulated function SetWeapAnimType(EWeapAnimType AnimType)
{
	if (AimNode != None)
	{
		switch(AnimType)
		{
			case EWAT_Default:
				AimNode.SetActiveProfileByName('Default');
				break;
			case EWAT_Pistol:
				AimNode.SetActiveProfileByName('SinglePistol');
				break;
			case EWAT_DualPistols:
				AimNode.SetActiveProfileByName('DualPistols');
				break;
			case EWAT_ShoulderRocket:
				AimNode.SetActiveProfileByName('ShoulderRocket');
				break;
			case EWAT_Stinger:
				AimNode.SetActiveProfileByName('Stinger');
				break;
		}
	}
}



//=============================================================================
// Default Properties
//=============================================================================
DefaultProperties
{
	Components.Remove(Sprite)

	Begin Object Class=x_Data_Pawn Name=DataInstance
	End Object
	Data = DataInstance

	Begin Object Class=DynamicLightEnvironmentComponent Name=PawnLightEnvironment
         AmbientGlow=(R=0.1,G=0.1,B=0.1,A=1.0)
         AmbientShadowColor=(R=0.0,G=0.0,B=0.0)
//         BouncedLightingFactor=0.0
         bSynthesizeSHLight=FALSE
         LightDistance=48
         ShadowDistance=0
         ModShadowFadeoutExponent=1
         bCastShadows=FALSE
		 bUseBooleanEnvironmentShadowing=FALSE
		 bShadowFromEnvironment=FALSE
//         ShadowFilterQuality=SFQ_Low
		 MinTimeBetweenFullUpdates = 0.3
		 bCompositeShadowsFromDynamicLights=FALSE
         bDynamic=TRUE
         MinShadowAngle=0
    End Object
    Components.Add(PawnLightEnvironment)
	LightEnvironment=PawnLightEnvironment

	Begin Object Class=SkeletalMeshComponent Name=PawnSkeletalMeshComponent		
		AlwaysLoadOnClient=TRUE
		AlwaysLoadOnServer=TRUE	
		BlockRigidBody=TRUE
		BlockActors=TRUE
		BlockZeroExtent=TRUE
		BlockNonZeroExtent=TRUE
		bAllowApproximateOcclusion=TRUE
		bForceDirectLightMap=TRUE	
		bCacheAnimSequenceNodes=FALSE
		bIgnoreControllersWhenNotRendered=FALSE
		bUpdateKinematicBonesFromAnimation=TRUE
		bCastDynamicShadow=TRUE
		bOwnerNoSee=FALSE	
		bChartDistanceFactor=TRUE
		bOverrideAttachmentOwnerVisibility=TRUE
		bAcceptsDecals=FALSE
		bAcceptsDynamicDecals=FALSE
		bHasPhysicsAssetInstance=TRUE
		bEnableFullAnimWeightBodies=TRUE
		bUpdateSkelWhenNotRendered=TRUE
		bUseAsOccluder=FALSE
		bUsePrecomputedShadows=FALSE
		CastShadow=TRUE
		CollideActors=TRUE
		LightEnvironment=PawnLightEnvironment
		LightingChannels=(Dynamic=TRUE,CompositeDynamic=TRUE)
		MinDistFactorForKinematicUpdate=0.2
		Translation=(X=0.0000000,Y=0.00000000,Z=0)		
		TickGroup=TG_PreAsyncWork
		RBChannel=RBCC_Pawn
		RBCollideWithChannels=(Default=TRUE,BlockingVolume=TRUE,GameplayPhysics=TRUE,EffectPhysics=TRUE,Vehicle=TRUE,Untitled3=TRUE, Pawn=TRUE)
		Scale=1.0		
	End Object
	Mesh=PawnSkeletalMeshComponent
	Components.Add(PawnSkeletalMeshComponent)

	Begin Object Name=CollisionCylinder
		CollisionRadius=+0025.000000
		CollisionHeight=+0045.000000
		BlockZeroExtent=FALSE
	End Object
	CylinderComponent=CollisionCylinder
	CollisionComponent=CollisionCylinder
	CollisionType=COLLIDE_BlockAll
	bCollideComplex = true //During Actor movement, ignore simplified collision (collision model) on this actor, and collide per-poly.
	bPathColliding = true //Whether this actor can block paths during AI path building in the editor.

	/** More accurate collision */
	/*
	Components.Remove(CollisionCylinder)
	CollisionComponent=PawnSkeletalMeshComponent
	CollisionType=COLLIDE_BlockAll
	bCollideComplex = true //During Actor movement, ignore simplified collision (collision model) on this actor, and collide per-poly.
	*/
	/** end */

	AlwaysRelevantDistanceSquared=+1960000.0
	//bPhysRigidBodyOutOfWorldCheck=TRUE
	bRunPhysicsWithNoController=TRUE
	bNoEncroachCheck=FALSE

	GroundSpeed=500.0
	SightRadius=1920
	RotationRate=(Pitch=0,Yaw=32768,Roll=0)

	bCanPickupInventory=TRUE
	InventoryManagerClass=Class'xLED_GAME.x_InventoryManager'
	
	WeaponSocket=Right_HandWeapon

	LeftFootControlName=LeftFootControl
	RightFootControlName=RightFootControl
	bEnableFootPlacement=TRUE
	MaxFootPlacementDistSquared=56250000.0 // 7500 squared

	DefaultPhysics = PHYS_Walking

	bIsDied = FALSE
}